-- DungeonEggM
-- Created by chengb Dec/30/2015
-- 迷宫中特殊彩蛋

module("DungeonEggM", package.seeall);

local PURE_FILE = "DungeonEggM";
local normalSubmitConfig = {};
local whenEnterUnreal;

local loadCsv = function()
    if _init then return end
    _init = true;

    normalSubmitConfig = {};

    local normal_submit_CSV = get_normal_submit_CSV();
    for i = 1, #normal_submit_CSV do
        local class = normal_submit_CSV[i].class;

        normalSubmitConfig[class] = normal_submit_CSV[i];
    end
end

-- 初始化
function init()
    loadCsv();

    EventMgr.removeAll(PURE_FILE);
    EventMgr.register(PURE_FILE, event.ENTER_UNREAL_DUNGEON, whenEnterUnreal);
end

-- 检索通用提交配置信息
function queryNormalSubmit(id, path)
    local m = normalSubmitConfig[id];
    if not m or path == "" or not path then
        return m;
    else
        return m[path];
    end
end

-- 进入夹层
whenEnterUnreal = function(para)
    local unrealId = para.unrealId;
    local dbase = UnrealDungeonM.query(unrealId, "dbase") or {};

    -- 如果是彩蛋
    if dbase["is_egg"] == 1 and type(dbase["egg_grid_class"]) == "number" then
        -- 增加统计
        statClassCount(dbase["egg_grid_class"]);
    end
end

-- 是否是特殊视力道具
function isSpecialVisionItem(classId)
    local targetList = FormulaM.invoke("GET_SPECIAL_VISION_ITEM");
    if type(targetList) ~= "table" or #targetList == 0 then
        -- 没有配置特殊视力道具
        return false;
    end
    return table.indexOf(targetList, classId) ~= -1;
end

-- 是否拥有特殊视力道具
function hasSpecialVisionItem()
    local targetList = FormulaM.invoke("GET_SPECIAL_VISION_ITEM");
    if type(targetList) ~= "table" or #targetList == 0 then
        -- 没有配置特殊视力道具
        return false;
    end

    for _, classId in pairs(targetList) do
        if ItemM.getAmount(ME.user, classId) > 0 then
            -- 包裹中有此道具
            return true;
        end

        if EquipM.isEquipment(classId) and EquipM.isEquiped(classId) then
            -- 是装备，并且穿戴在身上
            return true;
        end
    end
    return false;
end

-- 是否穿戴了特殊视力道具
function hasEquipedVisionItem()
    local targetList = FormulaM.invoke("GET_SPECIAL_VISION_ITEM");
    if type(targetList) ~= "table" or #targetList == 0 then
        -- 没有配置特殊视力道具
        return false;
    end

    for _, classId in pairs(targetList) do
        if EquipM.isEquipment(classId) and EquipM.isEquiped(classId) then
            -- 是装备，并且穿戴在身上
            return true;
        end
    end

    return false;
end

-- 领取古老的保险箱奖励
function takeOldStrongboxBonus(pos)
    local grid = DungeonM.getGridByPos(pos);
    if not grid then
        trace(PURE_FILE, "格子(%d)不存在", pos);
        return false;
    end

    if grid.type ~= GRID_TYPE_OLD_STRONGBOX then
        trace(PURE_FILE, "格子(%d)不是古老的保险箱", pos);
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        trace(PURE_FILE, "格子(%d)已经失效", pos);
        return false;
    end

    -- 计算奖励
    local bonus = FormulaM.invoke("CALC_OLD_STRONG_BONUS", ME.user);
    bonus = bonus["bonus"];

    -- 获取当前黄金罐数量
    local bonusInfo = bonus[1];
    local curNum = DungeonEggM.getTotleNumByType(bonusInfo);

    -- 执行奖励
    if type(bonus) == "table" and #bonus > 0 then
        for _, perBonus in pairs(bonus) do
            BonusM.doBonus(perBonus, "old_strongbox");
        end

        -- 成功了，把格子设置为失效
        grid:changeState(GRID_STATE_DISABLE);
    end

    -- 统计一下
    statClassCount(grid.class);

    -- 抛出事件
    -- 因为按策划的需求，飞入的奖励可能是按批次的（比如：钻石奖励30个，那么每批5个，共6批飞入）
    -- 由于显示的当前数量在逻辑层一次就处理好了，由于显示要求（数量逐渐递增）
    -- 因此在这里对当前拥有的数量做一个本地缓存
    for i, c in pairs(bonus) do
        if #c > 0 then
            curNum = curNum + c[3];

            local isDisappear = (i == 1) and true or false;
            EventMgr.fire(event.OLD_SAFE_BOX_BONUS, {
                ["pos"]         = pos,
                ["bonus"]       = c,
                ["curNum"]      = curNum,
                ["index"]       = i,
                ["isDisappear"] = isDisappear,
            });
        end
    end
    return true;
end

-- 执行东方神龛提交事件
function doEastShrineEvent(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid then
        trace(PURE_FILE, "格子(%d)不存在", pos);
        return false;
    end

    if grid.type ~= GRID_TYPE_EAST_SHRINE then
        trace(PURE_FILE, "格子(%d)不是东方神龛", pos);
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        trace(PURE_FILE, "格子(%d)已经失效", pos);
        return false;
    end

    if ItemM.getAmount(ME.user, classId) <= 0 then
        trace(PURE_FILE, "物品(%d)数量不足", classId);
        return false;
    end

    -- 扣除物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 计算奖励
    local isSucc;
    local bonus = FormulaM.invoke("CALC_EAST_SHRINE_BONUS", ME.user, classId);

    if type(bonus) == "table" and #bonus > 0 then
        BonusM.doBonus(bonus, "east_shrine");
        isSucc = true;

        statClassCount(grid.class);

        -- 如果成功了，将格子设置为失效
        if grid.multi_submit ~= 1 then
            grid:changeState(GRID_STATE_DISABLE);
        end
    else
        isSucc = false;
    end

    -- 抛出事件
    EventMgr.fire(event.EAST_SHRINE_SUBMIT, { ["pos"] = pos, ["classId"] = classId, ["bonus"] = bonus, ["isSucc"] = isSucc, });
    return true;
end

-- 执行机械祭坛提交事件
function doMachineAltarEvent(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid then
        trace(PURE_FILE, "格子(%d)不存在", pos);
        return false;
    end

    if grid.type ~= GRID_TYPE_MACHINE_ALTAR then
        trace(PURE_FILE, "格子(%d)不是机械祭坛", pos);
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        trace(PURE_FILE, "格子(%d)已经失效", pos);
        return false;
    end

    if ItemM.getAmount(ME.user, classId) <= 0 then
        trace(PURE_FILE, "物品(%d)数量不足", classId);
        return false;
    end

    -- 扣除物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 计算奖励
    local isSucc;
    local bonus = FormulaM.invoke("CALC_MACHINE_ALTAR_BONUS", ME.user, classId);

    if type(bonus) == "table" and #bonus > 0 then
        BonusM.doBonus(bonus, "machine_altar");
        isSucc = true;

        -- 统计
        statClassCount(grid.class);

        -- 如果成功了，将格子设置为失效
        grid:changeState(GRID_STATE_DISABLE)
    else
        isSucc = false;
    end

    -- 抛出事件
    EventMgr.fire(event.MACHINE_ALTAR_SUBMIT, { ["pos"] = pos, ["classId"] = classId, ["bonus"] = bonus, ["isSucc"] = isSucc, });
    return true;
end

-- 执行通用提交道具建筑提交事件
function doNormalSubmitEvent(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid then
        trace(PURE_FILE, "格子(%d)不存在", pos);
        return false;
    end

    if grid.type ~= GRID_TYPE_NORMAL_SUBMIT then
        trace(PURE_FILE, "格子(%d)不是通用提交道具建筑", pos);
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        trace(PURE_FILE, "格子(%d)已经失效", pos);
        return false;
    end

    local info = queryNormalSubmit(grid.class);

    if type(info) ~= "table" then
        trace(PURE_FILE, "没有格子(%d)的通用提交配置", grid.class);
        return false;
    end

    -- 如果提交需要消耗，则判断下是否支付得起消耗
    if type(info["submit_cost"]) == "table" then
        for _, cost in ipairs(info["submit_cost"]) do
            if cost[1] == 2 then
                if ME.user.dbase:query(cost[2], 0) < cost[3] then
                    -- 属性不足
                    alert(string.format(getLocStr("something_not_enough"), FieldsM.query(cost[2], "name")));
                    return false;
                end
            else
                if ItemM.getAmount(ME.user, cost[2]) < cost[3] then
                    -- 道具不足
                    alert(string.format(getLocStr("something_not_enough"), ItemM.query(cost[2], "name")));
                end
            end
        end
    end

    if ItemM.getAmount(ME.user, classId) <= 0 then
        trace(PURE_FILE, "物品(%d)数量不足", classId);
        return false;
    end

    -- 扣除物品
    DungeonServiceM.costDungeonItem(classId, 1);

    -- 扣除提交消耗
    if type(info["submit_cost"]) == "table" then
        for _, cost in ipairs(info["submit_cost"]) do
            if cost[1] == 2 then
                -- 消耗属性
                DungeonServiceM.costDungeonAttrib({[cost[2]] = cost[3]});
            else
                -- 消耗道具
                ItemM.costAmount(ME.user, cost[2], cost[3]);
            end
        end
    end

    -- 计算奖励
    local isSucc;
    local bonus = FormulaM.invoke(info["bonus_formula"], ME.user, grid.class, classId);

    if type(bonus) == "table" and #bonus > 0 then
        if type(bonus[1]) == "table" then
            for _, arr in ipairs(bonus) do
                BonusM.doBonus(arr, "normal_submit");
            end
        else
            BonusM.doBonus(bonus, "normal_submit");
        end
        isSucc = true;

        -- 统计
        statClassCount(grid.class);

        -- 如果成功了，将格子设置为失效
        if info["multi_submit"] ~= 1 then
            grid:changeState(GRID_STATE_DISABLE)
        end
    else
        isSucc = false;
    end

    -- 抛出事件
    EventMgr.fire(event.NORMAL_SUBMIT, { ["pos"] = pos, ["classId"] = classId, ["bonus"] = bonus, ["isSucc"] = isSucc, });
    return true;
end

-- 执行乌龟大师提交事件
function doMasterOogwayEvent(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid then
        trace(PURE_FILE, "格子(%d)不存在", pos);
        return false;
    end

    if grid.type ~= GRID_TYPE_MASTER_OOGWAY then
        trace(PURE_FILE, "格子(%d)不是乌龟大师", pos);
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        trace(PURE_FILE, "格子(%d)已经失效", pos);
        return false;
    end

    if ItemM.getAmount(ME.user, classId) <= 0 then
        trace(PURE_FILE, "物品(%d)数量不足", classId);
        return false;
    end

    -- 计算奖励
    local isSucc;
    local bonus = FormulaM.invoke("CALC_MASTER_OOGWAY_BONUS", ME.user, classId);
    local desc = "master_oogway";

    -- 成功给予奖励,扣除物品;失败拦截住
    if type(bonus) == "table" then
        -- 扣除物品
        DungeonServiceM.costDungeonItem(classId, 1);

        -- 给予奖励
        for key, info in pairs(bonus) do
            if key == "prop" then
                if info[4] ~= -1 then
                    info[4] = info[4] + round;
                end

                -- 拈花指持续整个迷宫特殊处理下
                local path = (info[1] == 598 and info[2] == 19) and "property_forever" or "mixed";
                PropM.record(ME.user, info, path);

            elseif key == "bonus" then
                if type(info[1]) == 'number' then
                    -- 只有一种奖励
                    BonusM.doBonus(info, desc);
                else
                    -- 有多种奖励
                    for _, bonus in pairs(info) do
                        BonusM.doBonus(bonus, desc);
                    end
                end
            end
        end

        -- 标记成功
        isSucc = true;

        -- 统计
        statClassCount(grid.class);

        -- 如果成功了，将格子设置为失效
        if grid.multi_submit ~= 1 then
            grid:changeState(GRID_STATE_DISABLE);
        end
    else
        isSucc = false;
    end

    -- 抛出事件
    EventMgr.fire(event.MASTER_OOGWAY_SUBMIT, { ["pos"] = pos, ["classId"] = classId, ["bonus"] = bonus, ["isSucc"] = isSucc, });
    return true;
end

-- 拆分奖励
function splitBonus(bonus)
    if nil == bonus then
        return nil;
    end

    -- 钻石每次飞入5颗,最后一批计算下真实剩余量
    local c = {};
    if "gem" == bonus[2] then
        local isRemain = (bonus[3] % 5 == 0);
        local num = isRemain and math.floor(bonus[3] / 5) or math.ceil(bonus[3] / 5);

        for i = 1, num - 1 do
            table.insert(c, {2, "gem", 5});
        end

        local remainNum = isRemain and 5 or (bonus[3] % 5);
        table.insert(c, {2, "gem", remainNum});
    -- 物品每次飞入1件
    elseif "number" == type(bonus[2]) then
        for i = 1, bonus[3] do
            table.insert(c, {1, bonus[2], 1});
        end
    -- 其它物品不飞入
    else
        return bonus;
    end

    return c;
end

-- 判断奖励类型，获得需要弹出侧边框的被奖励物件的当前总量
-- @param bonus  获得的奖励，它的数据结构举例：{2, "gem", 5}
-- 2:表示类型为属性，具体查get_bonus_CSV
-- "gem":表示是钻石
-- 5:表示数量为5
function getTotleNumByType(bonus)
    local totalNum = 0;

    -- 物品
    if bonus[1] == 1 then
        totalNum = ItemM.getAmount(ME.user, bonus[2]);
    -- 属性
    elseif bonus[1] == 2 then
        if bonus[2] == "money" then
            totalNum = ME.user.dbase:query("money", 0);
        elseif bonus[2] == "gem" then
            totalNum = ME.user.dbase:query("gem", 0);
        elseif bonus[2] == "soul_collect" then
            totalNum = ME.user.dbase:query("soul_collect", 0);
        elseif bonus[2] == "vital_essence" then
            totalNum = ME.user.dbase:query("vital_essence", 0);
        end
    end

    return totalNum;
end

-- 统计彩蛋格子出现次数
function statClassCount(class)
    local stat = ME.user.dbase:query("dungeon_egg_stat", {});
    stat[class] = (stat[class] or 0) + 1;

    ME.user.dbase:set("dungeon_egg_stat", stat);
end

-- 领取反叛军奖励
function takeRebelsBonus(pos)
    local grid = DungeonM.getGridByPos(pos);

    if not grid or grid.state == GRID_STATE_DISABLE
        or grid.type ~= GRID_TYPE_REBELS then
        trace(PURE_FILE, "格子(%d)不是反叛军或者已经失效", pos);
        return false;
    end

    local classId = grid.class_id;
    if type(classId) ~= "number" then
        trace(PURE_FILE, "格子(%d)没有提交物品信息", pos);
        return false;
    end

    -- 计算奖励
    local bonus = FormulaM.invoke("CALC_REBELS_BONUS", ME.user, classId);
    local desc = "rebels_submit";

    if type(bonus[1]) == 'number' then
        -- 只有一种奖励
        BonusM.doBonus(bonus, desc);
    else
        -- 有多种奖励
        for _, perBonus in pairs(bonus) do
            BonusM.doBonus(perBonus, desc);
        end
    end

    local disappear = false;
    if FormulaM.invoke("CALC_REBELS_BONUS_DISABLE", ME.user, classId) then
        -- 把格子设置为失效
        grid:changeState(GRID_STATE_DISABLE);
        disappear = true;
    end


    -- 抛出事件
    EventMgr.fire(event.REBELS_BONUS, {["bonus"] = bonus, ["pos"] = pos, ["disappear"] = disappear});

    return true;
end

-- 向反叛军提交物品
function rebelsSubmit(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid or grid.state == GRID_STATE_DISABLE
        or grid.type ~= GRID_TYPE_REBELS then
        trace(PURE_FILE, "格子(%d)不是反叛军或者已经失效", pos);
        return false;
    end

    -- 记录下提交的物品
    grid.class_id = classId;

    -- 扣除玩家物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 直接领奖
    takeRebelsBonus(pos);

    return true;
end

-- 向奇怪的电脑提交物品
function strangePCSubmit(pos, classId)
    local grid = DungeonM.getGridByPos(pos);
    if not grid or grid.state == GRID_STATE_DISABLE
        or grid.type ~= GRID_TYPE_STRANGE_PC then
        trace(PURE_FILE, "格子(%d)不是奇怪的电脑或者已经失效", pos);
        return false;
    end

    -- 战争芯片/改造芯片X1000
    if table.indexOf(grid.submited, classId) < 0 then
        trace(PURE_FILE, "物品(%d)不是奇怪的电脑可提交物品", classId);
        return false;
    end

    -- 扣除玩家物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 直接领奖
    DungeonServiceM.addDungeonAttrib("arsenal_gate_open", 1);

    grid:changeState(GRID_STATE_DISABLE);

    return true;
end